package com.tang.script.extrator;

import com.tang.script.command.AbstractScriptCommand;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

public class FunctionsExtractor {
    private static final FunctionsExtractor functionsExtractor = new FunctionsExtractor();

    public static FunctionsExtractor get() {
        return functionsExtractor;
    }

    public void extracte(AbstractScriptCommand command) {
        LinkedList<FunctionDefinition> functionDefinitions = new LinkedList<>();
        String resolvedScriptText = command.getResolvedScriptText();
        Set<String> functions = new HashSet<String>();
        char[] chars = resolvedScriptText.toCharArray();
        int i = chars.length - 1;
        while (i >= 0) {
            while (i >= 0 && chars[i] != '(') i--;
            int j = i;
            i--;
            while (i >= 0 && isFunctionChar(chars[i])) i--;
            if (j > i + 1) {
                String name = resolvedScriptText.substring(i + 1, j);
                functions.add(name);
                functionDefinitions.add(new FunctionDefinition(i + 1, j, name));
            }
        }

        command.setFunctions(new LinkedList<>(functions));
        resolvedScriptText = renameInvokeMethods(functionDefinitions, resolvedScriptText);
        command.setResolvedScriptText(resolvedScriptText);
    }

    private String renameInvokeMethods(LinkedList<FunctionDefinition> functionDefinitions, String resolvedScriptText) {
        StringBuilder stringBuilder = new StringBuilder(resolvedScriptText);

        while (!functionDefinitions.isEmpty()) {
            FunctionDefinition functionDefinition = functionDefinitions.removeFirst();
            stringBuilder.insert(functionDefinition.end, "." + functionDefinition.getName());
        }
        return stringBuilder.toString();
    }

    @AllArgsConstructor
    @Getter
    @Setter
    class FunctionDefinition {
        int start;
        int end;
        String name;
    }

    private boolean isFunctionChar(char c) {
        if (c >= 'a' && c <= 'z') return true;
        if (c >= 'A' && c <= 'Z') return true;
        if (c >= '0' && c <= '9') return true;
        return false;
    }
}
